package com.github.binarywang.demo.wechat.controller;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestOperations;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.demo.wechat.config.WxCpProperties;
import com.github.binarywang.demo.wechat.entity.User;
import com.github.binarywang.demo.wechat.entity.WxUserDetail;
import com.github.binarywang.demo.wechat.service.UserService;
import com.github.binarywang.demo.wechat.shiro.JwtTokenUtil;
import com.github.binarywang.demo.wechat.shiro.JwtUser;
import com.github.binarywang.demo.wechat.shiro.JwtUserFactory;
import com.github.binarywang.demo.wechat.utils.R;

@RestController
@RequestMapping("/wx/auth")
@EnableConfigurationProperties(WxCpProperties.class)
public class WxIndexController {

	public static String access_token;// 主动调用：发送消息获得token

	public static Date access_token_date;// 主动调用：请求token的时间
	public static final String URL_CODE = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={CORPID}&redirect_uri={REDIRECT_URI}&response_type=code&scope=snsapi_privateinfo&agentid={AGENTID}&state=STATE#wechat_redirect";
	public static final String URL_USERINFO = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token={ACCESS_TOKEN}&code={CODE}"; // 获取员工信息
	private static final String URL_USERDETAIL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail?access_token={ACCESS_TOKEN}"; // 获取员工详细信息

	@Autowired
	private WxCpProperties properties;
	@Autowired
	private RestOperations restOperations;
	@Autowired
	private JwtTokenUtil jwtTokenUtil;
	@Autowired
	private UserService userService;

	@Value("${jwt.header}")
	private String header; // 定义密码

	@GetMapping(path = "/wxIndex")
	public void wxIndex(@RequestParam(name = "code", required = false) String code, HttpServletRequest request,
			HttpServletResponse response) {
		System.out.println(code);
		try {
			String token = ""; // 准备返回的Token
			Map<String, Object> uriVariables = new HashMap<String, Object>(); // 参数
			uriVariables.clear();
			uriVariables.put("CODE", code);
			uriVariables.put("ACCESS_TOKEN", getTokenFromWx());
			JSONObject result = restOperations.getForObject(URL_USERINFO, JSONObject.class, uriVariables); // 获取来访人的User
			String wxUserId = (String) result.get("UserId");
			// 通过UserId到我们的数据库中进行查询，如果已经与用户进行关联则返回用户信息,创建Token
			User user = userService.queryByWXUserId(wxUserId);
			if (user == null) {// 如果UserID没有在数据库中，到微信获取人员的详细信息
				String user_ticket = result.get("user_ticket").toString();
				uriVariables.clear();
				uriVariables.put("ACCESS_TOKEN", getTokenFromWx());
				JSONObject postData = new JSONObject();
				postData.put("user_ticket", user_ticket);
				result = restOperations.postForEntity(URL_USERDETAIL, postData, JSONObject.class, uriVariables)
						.getBody();
				WxUserDetail wxUserDetail = JSON.parseObject(result.toJSONString(), WxUserDetail.class);
				// 通过人员详细信息中的手机号码查询数据库人员如果手机号码存在，则将UserID绑定到数据库用户
				user = userService.queryAndBindByMobile(wxUserDetail, wxUserId);
			}
			// if (user == null) {
			// // 如果数据库中连人员手机号码都不存在，则返回错误信息，要求联系管理员进行微信通讯录的维护工作
			// return R.error(401, "用户登录失败,请与系统管理员联系!");
			// }
			// if (user.getStatus() != User.STATUS_1) {
			// return R.error(401, "帐号已冻结");
			// }
			JwtUser jwtUser = JwtUserFactory.create(user);
			token = jwtTokenUtil.generateToken(jwtUser);
			Cookie cookie = new Cookie("token", token);// 创建新cookie
			cookie.setMaxAge(5 * 60);// 设置存在时间为5分钟
			cookie.setPath("/");// 设置作用域
			response.addCookie(cookie);// 将cookie添加到response的cookie数组中返回给客户端
			response.sendRedirect("http://zhimakaimen.tunnel.qydev.com");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@ResponseBody
	@RequestMapping(value = "/obtainToken")
	public R obtainToken(String code, HttpServletRequest request, HttpServletResponse response) throws Exception {
		String token = ""; // 准备返回的Token
		Map<String, Object> uriVariables = new HashMap<String, Object>(); // 参数
		uriVariables.clear();
		uriVariables.put("CODE", code);
		JSONObject result = restOperations.getForObject(URL_USERINFO, JSONObject.class, uriVariables); // 获取来访人的User
		System.out.println("获取到的员工ID" + result.get("UserId"));
		String wxUserId = (String) result.get("UserId");
		// 通过UserId到我们的数据库中进行查询，如果已经与用户进行关联则返回用户信息,创建Token
		User user = userService.queryByWXUserId(wxUserId);
		if (user == null) {// 如果UserID没有在数据库中，到微信获取人员的详细信息
			String user_ticket = result.get("user_ticket").toString();
			uriVariables.clear();
			uriVariables.put("ACCESS_TOKEN", getTokenFromWx());
			JSONObject postData = new JSONObject();
			postData.put("user_ticket", user_ticket);
			result = restOperations.postForEntity(URL_USERDETAIL, postData, JSONObject.class, uriVariables).getBody();
			WxUserDetail wxUserDetail = JSON.parseObject(result.toJSONString(), WxUserDetail.class);
			// 通过人员详细信息中的手机号码查询数据库人员如果手机号码存在，则将UserID绑定到数据库用户
			user = userService.queryAndBindByMobile(wxUserDetail, wxUserId);
		}
		if (user == null) {
			// 如果数据库中连人员手机号码都不存在，则返回错误信息，要求联系管理员进行微信通讯录的维护工作
			return R.error(401, "用户登录失败,请与系统管理员联系!");
		}
		if (user.getStatus() != User.STATUS_1) {
			return R.error(401, "帐号已冻结");
		}
		JwtUser jwtUser = JwtUserFactory.create(user);
		token = jwtTokenUtil.generateToken(jwtUser);
		return R.ok().put("token", token);
	}

	/**
	 * 从微信获得access_token
	 * 
	 * @return
	 */
	public String getTokenFromWx() {
		// 获取的标识
		String token = "";
		// 1、判断access_token是否存在，不存在的话直接申请
		// 2、判断时间是否过期，过期(>=7200秒)申请，否则不用请求直接返回以后的token
		if (null == access_token || "".equals(access_token)
				|| (new Date().getTime() - access_token_date.getTime()) >= (7000 * 1000)) {
			try {
				Map<String, Object> uriVariables = new HashMap<String, Object>();
				String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}";
				uriVariables.put("corpid", properties.getCorpId());
				uriVariables.put("corpsecret", properties.getSecret());
				JSONObject resultToken = restOperations.getForObject(url, JSONObject.class, uriVariables);
				token = resultToken.get("access_token").toString();
				access_token = token;
				access_token_date = new Date();
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			token = access_token;
		}
		return token;
	}

	/**
	 * 刷新获取Token方法
	 *
	 * @param request
	 * @return
	 */
	@GetMapping(value = "refresh")
	public R refreshAndGetAuthenticationToken(HttpServletRequest request) {
		// 获取请求头（配置文件中jwt.header的值）,实际就是当前使用的Token

		String token = request.getHeader(header);
		// 获取Token中的用户名（jwtTokenUtil具备这个功能）
		String username = jwtTokenUtil.getUsernameFromToken(token);
		// 通过用户名从后台数据库中获取用户对象并强制转换成JWTUser对象，正常返回的是UserDetails对象

		User userInfo = userService.queryByUserName(username);
		JwtUser user = JwtUserFactory.create(userInfo);
		// 将验证任务交给jwtTokenUtil进行处理，
		// 如果Token有效并且可以认证通过则将新Token返回前台，
		// 否则，返回错误
		if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
			String refreshedToken = jwtTokenUtil.refreshToken(token);
			return R.ok().put("token", refreshedToken);
		} else {
			return R.error(401, "刷新Token失败");
		}
	}

}
